package org.chenwang.projects.ehcacheaws;

import java.io.File;
import java.util.Properties;

import net.sf.ehcache.util.PropertyUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jets3t.service.S3ServiceException;
import org.jets3t.service.security.AWSCredentials;

/**
 * The class encapsulates S3 related configurations, and also provides parsing
 * helper class to read configurations from Ehcache.
 *
 */
public class AmazonS3Configuration {

	private static final Log log = LogFactory.getLog(AmazonS3Configuration.class);
	
	
	public static final String VALUE_DEFAULT_BUCKET_NAME = "ehcache";
	
	public static final String VALUE_DEFAULT_PATH_SEPARATOR = "/";
	
	public static final String VALUE_DEFAULT_PATH_NAME = "ehcache";
	
	public static final String VALUE_DEFAULT_KEY_FILE = "aws_keys.jets3t";
	
	public static final String VALUE_DEFAULT_KEY_PASS = "jets3t";
	
	public static final boolean VALUE_DEFAULT_MULTITHREADED = false;
	
	
	public static final String NAME_BUCKET_NAME = "bucketName";
	
	public static final String NAME_PATH_NAME = "pathName";
	
	public static final String NAME_PATH_SEPARATOR = "pathSeparator";
	
	public static final String NAME_ACCESS_KEY = "accessKey";
	
	public static final String NAME_SECRET_KEY = "secretKey";
	
	public static final String NAME_KEY_FILE = "keyFile";
	
	public static final String NAME_KEY_PASS = "keyPass";
	
	public static final String NAME_MULTITHREADED = "multithreaded";
	
	
	private String bucketName;
	
	private String pathName;
	
	private String pathSeparator;
	
	private AWSCredentials credentials;
	
	private boolean multithreaded;
	

	public AmazonS3Configuration(String bucketName, String pathName,
			String pathSeparator, AWSCredentials credentials,
			boolean multithreaded) {
		super();
		this.bucketName = bucketName;
		this.pathName = pathName;
		this.pathSeparator = pathSeparator;
		this.credentials = credentials;
		this.multithreaded = multithreaded;
	}

	public String getBucketName() {
		return bucketName;
	}

	public String getPathName() {
		return pathName;
	}

	public String getPathSeparator() {
		return pathSeparator;
	}

	public AWSCredentials getCredentials() {
		return credentials;
	}

	public boolean isMultithreaded() {
		return multithreaded;
	}
	
	public static AmazonS3Configuration parse(Properties properties) {
		
		AmazonS3Configuration configuration = null;
		
		boolean hasError = false;
		
		// bucket name.
		String bn = VALUE_DEFAULT_BUCKET_NAME;
		log.info("loaded default value for [" + NAME_BUCKET_NAME + "] [" + bn + "]");
		String bnv = PropertyUtil.extractAndLogProperty(NAME_BUCKET_NAME, properties);
		if (bnv != null) {
			bn = bnv;
			log.info("used configured value [" + bn + "]");
		}
		
		// path separator.
		String ps = VALUE_DEFAULT_PATH_SEPARATOR;
		log.info("loaded default value for [" + NAME_PATH_SEPARATOR + "] [" + ps + "]");
		String psv = PropertyUtil.extractAndLogProperty(NAME_PATH_SEPARATOR, properties);
		if (psv != null) {
			ps = psv;
			log.info("used configured value [" + ps + "]");
		}
		
		// path name.
		String pn = VALUE_DEFAULT_PATH_NAME;
		log.info("loaded default value for [" + NAME_PATH_NAME + "] [" + pn + "]");
		String pnv = PropertyUtil.extractAndLogProperty(NAME_PATH_NAME, properties);
		if (pnv != null) {
			pn = pnv;
			log.info("used configured value [" + pn + "]");
		}
		else {
			log.warn("It is strongly recommended to set [" + NAME_PATH_NAME + "]!");
		}
		
		// AWS credentials.
		AWSCredentials credentials = null;
		
		// if key file and pass are available then use them firstly.
		String kf = VALUE_DEFAULT_KEY_FILE;
		log.info("loaded default value for [" + NAME_KEY_FILE + "] [" + kf + "]");
		String kfv = PropertyUtil.extractAndLogProperty(NAME_KEY_FILE, properties);
		if (kfv != null) {
			kf = kfv;
			log.info("used configured value [" + kf + "]");
		}
		String kp = VALUE_DEFAULT_KEY_PASS;
		String kpv = PropertyUtil.extractAndLogProperty(NAME_KEY_PASS, properties);
		log.info("loaded default value for [" + NAME_KEY_PASS + "] [" + kp + "]");
		if (kpv != null) {
			kp = kpv;
			log.info("used configured value [" + kp + "]");
		}
		
		try {
			credentials = AWSCredentials.load(kp, new File(kf));
			log.info("loaded aws credentials from file");
		}
		catch (S3ServiceException s3se) {
			log.warn("There was a problem loading AWS credentials from encrypted key file", s3se);
		}
		
		if (credentials == null) {
			// if clear keys are available then use them in case of key file/pass being unavailable.
			String ak = PropertyUtil.extractAndLogProperty(NAME_ACCESS_KEY, properties);
			String sk = PropertyUtil.extractAndLogProperty(NAME_SECRET_KEY, properties);
			if (ak == null || sk == null) {
				log.error("Both [" + NAME_ACCESS_KEY + "] and [" + NAME_SECRET_KEY + "] are needed to load AWS credentials!");
				hasError = true;
			}
			else {
				credentials = new AWSCredentials(ak, sk);
				log.info("loaded aws credentials using keys");
			}
		}
		
		if (credentials == null) {
			// if still not available then no recovery plan is available.
			log.error("It is not possible to load AWS credentials!");
			hasError = true;
		}
		
		// multithreaded or not which will decide the underlying implementation.
		boolean m = VALUE_DEFAULT_MULTITHREADED;
		log.info("loaded default value for [" + NAME_MULTITHREADED + "] [" + m + "]");
		String mv = PropertyUtil.extractAndLogProperty("NAME_MULTITHREADED", properties);
		if (mv != null) {
			m = PropertyUtil.parseBoolean(mv);
			log.info("used configured value [" + m + "]");
		}
		
		if (! hasError) {
			configuration = new AmazonS3Configuration(bn, pn, ps, credentials, m);
			log.info("created configuration object for S3");
		}
		
		return configuration;
	}
}
